package com.transfiguro.visitors;

import com.transfiguro.datamodel.javamodels.Method;
import com.transfiguro.utilities.Utilities;
import japa.parser.ast.body.MethodDeclaration;
import japa.parser.ast.stmt.BlockStmt;
import japa.parser.ast.stmt.Statement;
import japa.parser.ast.visitor.VoidVisitorAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * This class provides methods to visit methods and create {@link Method}s out of it
 */
public class MethodVisitor extends VoidVisitorAdapter {
    private final Logger logger = LoggerFactory.getLogger(MethodVisitor.class);
    private List<Method> methodList;
    private StatementVisitor statementVisitor;
    private List<com.transfiguro.datamodel.Statement> statements;

    /**
     * Constructor
     */
    public MethodVisitor() {
        methodList = new ArrayList<Method>();
        statementVisitor = new StatementVisitor();
    }

    /**
     * This method visits different nodes in a given {@link MethodDeclaration} and builds a
     * {@link Method} out of it
     *
     * @param declaration  The <code>MethodDeclaration</code> to be visited
     * @param arg          Optional argument that can be used to pass anything into
     *                    the function. Current implementation uses this to indicate
     *                    if a method belongs to an interface or not by passing in a boolean.
     *                    <tt>True</tt> indicates that the method belongs to an interface
     *                    <tt>False</tt> indicates that the method does not belong to an interface
     */
    @Override
    public void visit(final MethodDeclaration declaration, final Object arg) {
        Method method = new Method();
        if (!(Boolean) arg) {
            statements = new ArrayList<com.transfiguro.datamodel.Statement>();
            method.setMethodName(declaration.getName());
            method.setInputParameters(Utilities.getInputParameters(declaration.getParameters()));
            method.setMethodBody(declaration.getBody().toString());
            final BlockStmt blockStmt = declaration.getBody();
            logger.info("Statements");
            if (blockStmt.getStmts() != null) {
                for (final Statement statement : blockStmt.getStmts()) {
                    method.addStatement(statementVisitor.visit(statement));
                }
            }
            logger.info("Statement List: {}\n{}", statements.size(), statements.toString());
            method.setAccessModifier(declaration.getModifiers());
            method.setReturnType(declaration.getType().toString());
            method.setComment(Utilities.getComment(declaration.getJavaDoc()));
        } else {
            method.setMethodName(declaration.getName());
            method.setInputParameters(Utilities.getInputParameters(declaration.getParameters()));
            method.setAccessModifier(declaration.getModifiers());
            method.setReturnType(declaration.getType().toString());
            method.setComment(Utilities.getComment(declaration.getJavaDoc()));
        }
        methodList.add(method);
    }

    /**
     * Getter for <code>methodList</code>
     *
     * @return  The <code>methodList</code> created by visiting the given
     *         </code>MethodDeclaration(s)</code>
     */
    public List<Method> getMethodList() {
        return methodList;
    }
}
